/******************************************************************************/
/* File: udpTrafficServer.cpp                                                 */
/******************************************************************************/

#include "udpTrafficServer.h"

UDPTrafficServer::UDPTrafficServer(TrafficServerSetting *pSet, MessageQueue *pMQ)
                : UDPServerSocket(pSet->bUseIPv6), pMsgQueue(pMQ){
    cListenIP.SetHostName(pSet->sHostName, pSet->bUseIPv6);
    iListenPort = pSet->iUdpTrafficServerListenPort;
    bUseIPv6 = pSet->bUseIPv6;
    mBuf = new char[DataStore::generalSetting.iUDPBufferLength];
    
    ListenServer();
}

UDPTrafficServer::~UDPTrafficServer() {
    
}

void UDPTrafficServer::ListenServer() {
    try {
        const int iReUseAddrFlag = 1;
		SetSockOpt(SOL_SOCKET, SO_REUSEADDR, &iReUseAddrFlag, sizeof(iReUseAddrFlag));
        
        Bind(cListenIP, iListenPort);
        GetSockName(cLocalAddress, iLocalPort);
        std::cout << "UDP traffic server is running...\n";
    } 
    catch (SocketException se) {
        se.PrintException();
        std::cout << "Cannot start UDP traffic server.\n";
        return;
    }
}

void UDPTrafficServer::CloseListenSocket() {
    CloseSocket();
}

/* ------------------------------------------------------------------- 
* Do the equivalent of an accept() call for UDP sockets. This waits 
* on a listening UDP socket until we get a datagram. 
* ------------------------------------------------------------------- */
UDPConnectedSocket* UDPTrafficServer::AcceptClient() {
    UDPConnectedSocket *pucs = new UDPConnectedSocket(bUseIPv6);
    ConnectionInfo *pci = new ConnectionInfo();
    int length = DataStore::generalSetting.iUDPBufferLength;
    while (!pucs->IsConnected()) {
        IPAddress remoteIP;
        int remotePort;
        ReceiveDatagram(mBuf, length, remoteIP, remotePort);
        
        pci->sSenderIP = (char *)remoteIP;
        pci->iSenderPort = remotePort;
        pci->sRecverIP = (char *)cListenIP;
        pci->iRecverPort = iListenPort;
        pci->iProto = 2;
        pci->iRole = 2;

        pthread_t tid = DataStore::FindFlowThread(pci);
        
        if(tid == -1) {
            int SelfSock = GetSockDesc();
            
            pucs->SetSockDesc(SelfSock);
            pucs->Connect(remoteIP, remotePort);
            
            return pucs;
        }
    }
}

void UDPTrafficServer::UploadRegisterInfo() {
	RegisterRequest *ptur = new RegisterRequest();
	
	ptur->iToRegister = 1; // to register
	ptur->iServProto = 2;  // udp
	ptur->sServIP = strdup((char *)cListenIP);
	ptur->iServPort = iListenPort;
	
	Request *pr = new Request();
	pr->iRequestType = 1;
	pr->pServerReg = ptur;
	
	Message *pm = new Message();
	pm->iMessageType = 1;
	pm->pRequest = pr;
	
	pMsgQueue->PushMessage(pm);
}

void UDPTrafficServer::UploadUnregisterInfo() {
    
	RegisterRequest *ptur = new RegisterRequest();
	
	ptur->iToRegister = 2; // to unregister
	ptur->iServProto = 2;  // udp
	ptur->sServIP = strdup((char *)cListenIP);
	ptur->iServPort = iListenPort;
	
	Request *pr = new Request();
	pr->iRequestType = 1;
	pr->pServerReg = ptur;
	
	Message *pm = new Message();
	pm->iMessageType = 1;
	pm->pRequest = pr;
	
	pMsgQueue->PushMessage(pm);
}

void UDPTrafficServer::ExitCleanUp() {
    UploadUnregisterInfo();
}

void UDPTrafficServer::Run() {
    
    UploadRegisterInfo();
    
    while (true) {
        
        UDPConnectedSocket *pucs;
        try {
            pucs = AcceptClient();
        }
        catch (SocketException se) {
            se.PrintException();
            ExitCleanUp();
            return;
        }
        
        std::cout << "Accept new UDP flow recevier instance...\n";
        
        // 建立新线程处理
        ConnectionInfo *pci = new ConnectionInfo();
        char *cip = pucs->RemoteHostName();
        char *sip = pucs->LocalHostName();
		pci->sSenderIP = strdup(cip);
		pci->sRecverIP = strdup(sip);
		pci->iSenderPort = pucs->RemotePortNumber();
		pci->iRecverPort = pucs->LocalPortNumber();
		pci->iProto = 2; // udp
		pci->iRole = 2; // server
        
        ThreadConf *ptc = new ThreadConf();
        ptc->pFC = NULL;
        ptc->pMQ = pMsgQueue;
        
        UDPTrafficRecver *pUdpRecver = new UDPTrafficRecver(pucs, ptc);
        pUdpRecver->Start(NULL);
        pUdpRecver->Detach();
        
        DataStore::AddNewFlowThread(dynamic_cast<Thread *>(pUdpRecver), pci, ptc);
        
        // 新建一个Listen套接字
        ResetSock();
        ListenServer();
    }
}

/******************************************************************************/
/* End File: udpTrafficServer.cpp                                             */
/******************************************************************************/